const formatTime = date => {
    const year = date.getFullYear()
    const month = date.getMonth() + 1
    const day = date.getDate()
    const hour = date.getHours()
    const minute = date.getMinutes()
    const second = date.getSeconds()

    return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':')
}

const formatNumber = n => {
    n = n.toString()
    return n[1] ? n : '0' + n
}

const is_object = function (obj) {
    return typeof obj === 'object' && !is_array(obj) && obj !== null;
};

const httpBuildQuery = function (data, p) {
    var querys = [];
    for (var k in data) {
        if (typeof data[k] === 'object') {
            querys.push(httpBuildQuery(data[k], p ? p + '[' + k + ']' : k));
        } else if (typeof data[k] === 'string' || typeof data[k] === 'number') {
            querys.push((p ? p + '[' + k + ']' : k) + '=' + encodeURIComponent(data[k]));
        } else if (typeof data[k] === 'boolean') {
            querys.push((p ? (p + '[' + k + ']') : k) + '=' + (data[k] ? 1 : 0));
        }
    }
    return querys.join('&');
};
const httpBuildUrl = function (url, data) {
    var query = httpBuildQuery(data);
    if (query) {
        return url + (url.indexOf('?') > -1 ? '&' : '?') + httpBuildQuery(data);
    } else {
        return url;
    }
};
const httpGetTrf = function (dd, kk) {
    var ks = [],
        kl = 0,
        vs = [];
    if (is_object(dd)) {
        for (var k in dd) {
            var i = parseInt(k);
            if (is_object(dd[k]) || is_array(dd[k])) {
                foreach(dd[k], httpGetTrf, dd[k]);
            }
            if (/^[0-9]+$/.test(k) && (k[0] !== '0' || k === '0') && ks.indexOf(i) < 0) {
                ks.push(i);
            }
            kl += 1, vs.push(dd[k]);
        }
        ks.sort();
        ks.length === kl && ks[0] === 0 && ks[kl - 1] === kl - 1 && (this[kk] = vs);
    }
}
const foreach = function (data, callback, self) {
    if (!data) {

    } else if (data.length === undefined) {
        for (var k in data) {
            if (callback.call(self, data[k], k) === true) {
                return data[k];
            }
        }
    } else {
        for (var i = 0; i < data.length; i++) {
            if (callback.call(self, data[i], i) === true) {
                return data[i];
            }
        }
    }
};
const httpUrlArgs = function (url) {
    var data = {},
        sear = (url || location.href).split('?')[1] || '';
    foreach(sear ? sear.split('&') : [], function (t) {
        var td = data;
        var ps = t.split('=');
        if (ps[0]) {
            var ks = ps[0].match(/\[([^]]*)\]/g);
            var nm = '[' + ps[0].match(/^[^[]+/)[0] + ']';
            var vs = decodeURIComponent(ps[1]);
            ks ? (ks.unshift(nm)) : (ks = [nm]);
            foreach(ks, function (k, i) {
                k = k.substring(1, k.length - 1);
                td[k] || (td[k] = (i === ks.length - 1) ? vs : {});
                td = td[k];
            });
        }
    });
    foreach(data, httpGetTrf, data);
    return data;
};
const is_func = function (callback) {
    return typeof callback === 'function';
};
/**
 * request
 */
const reqConfig = require('../config/payConfig').reqConfig;
const request = function (url, { data, callback, failback, type, headers }) {
    wx.request({
        url,
        data,
        header: headers,
        method: data ? 'POST' : 'GET',
        dataType: type || 'json',
        success: callback,
        fail: failback
    })
};
request.rpc = function (namespace, params, callback, route, hostname, headers) {
    return new Promise(function (resolve, reject) {
        var nas = namespace.split('\\');
        var protocol = reqConfig.protocol || 'http';
        var api = protocol + '://' + (hostname ? hostname : reqConfig.hostname) + '' + (route || '/api');
        var post = {
            method: nas.pop(),
            service: nas.join('\\'),
            params
        };
        request(api, {
            data: post,
            callback: function (res) {
                is_func(callback) && callback(res.data);
                if (res.data.status === 1) {
                    res.data.data._info = res.data.info;
                    resolve(res.data.data)
                } else {
                    reject(res.data)
                }
            },
            failback: function (err) {
                wx.showToast({
                    title: '数据请求失败，请重试',
                    icon: 'none'
                })
                reject(err)
            },
            type: 'json',
            headers: headers || {}
        });
    });
};

const wxPromiseApi = function (apiName, options = {}) {
    return new Promise((resolve, reject) => {
        const opt = Object.assign({}, options, {
            success: (res) => {
                is_func(options.success) && options.success(res);
                resolve(res);
            },
            fail: (err) => {
                is_func(options.fail) && options.fail(err);
                reject(err);
            }
        });

        wx[apiName](opt)
    });
};

// 可传入过期时间的storage缓存, time单位为秒
const wxStorage = {
    setStorage: (key, value, time) => {
        wx.setStorageSync(key, {
            value,
            time,
            start: new Date().getTime()
        })
    },
    getStorage: (key) => {
        const now = new Date().getTime();
        const value = wx.getStorageSync(key);
        if (!value) return null;
        if (value.time && (now - value.start > Number(value.time) * 1000)) {
            wx.clearStorageSync(key);
            return null;
        }
        console.log(value.value);
        return value.value;
    }
}

/**
 *  判断经纬度是否超出中国境内
 */
function isLocationOutOfChina (latitude, longitude) {
    if (longitude < 72.004 || longitude > 137.8347 || latitude < 0.8293 || latitude > 55.8271)
        return true;
    return false;
}


/**
 *  将WGS-84(国际标准)转为GCJ-02(火星坐标):
 */
function transformFromWGSToGCJ (latitude, longitude) {
    var lat = "";
    var lon = "";
    var ee = 0.00669342162296594323;
    var a = 6378245.0;
    var pi = 3.14159265358979324;

    if (isLocationOutOfChina(latitude, longitude)) {
        lat = latitude;
        lon = longitude;
    } else {
        var adjustLat = transformLatWithXY(longitude - 105.0, latitude - 35.0);
        var adjustLon = transformLonWithXY(longitude - 105.0, latitude - 35.0);
        var radLat = latitude / 180.0 * pi;
        var magic = Math.sin(radLat);
        magic = 1 - ee * magic * magic;
        var sqrtMagic = Math.sqrt(magic);
        adjustLat = (adjustLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);
        adjustLon = (adjustLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi);
        latitude = latitude + adjustLat;
        longitude = longitude + adjustLon;
    }
    return { latitude: latitude, longitude: longitude };

}

function transformLatWithXY (x, y) {
    var pi = 3.14159265358979324;
    var lat = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x));
    lat += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
    lat += (20.0 * Math.sin(y * pi) + 40.0 * Math.sin(y / 3.0 * pi)) * 2.0 / 3.0;
    lat += (160.0 * Math.sin(y / 12.0 * pi) + 320 * Math.sin(y * pi / 30.0)) * 2.0 / 3.0;
    return lat;
}

function transformLonWithXY (x, y) {
    var pi = 3.14159265358979324;
    var lon = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));
    lon += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
    lon += (20.0 * Math.sin(x * pi) + 40.0 * Math.sin(x / 3.0 * pi)) * 2.0 / 3.0;
    lon += (150.0 * Math.sin(x / 12.0 * pi) + 300.0 * Math.sin(x / 30.0 * pi)) * 2.0 / 3.0;
    return lon;
}

//事件总线
class PubSub {
    constructor() {
        this.PubSubCache = {
            $uid: 0
        };
    }

    on(type, handler) {
        let cache = this.PubSubCache[type] || (this.PubSubCache[type] = {});
        handler.$uid = handler.$uid || this.PubSubCache.$uid++;
        cache[handler.$uid] = handler;
    }

    emit(type, ...param) {
        let cache = this.PubSubCache[type],
            key,
            tmp;
        if (!cache) return;
        for (key in cache) {
            tmp = cache[key];
            cache[key].call(this, ...param);
        }
    }

    off(type, handler) {
        let counter = 0,
            $type,
            cache = this.PubSubCache[type];
        if (handler == null) {
            if (!cache) return true;
            return !!this.PubSubCache[type] && (delete this.PubSubCache[type]);
        } else {
            !!this.PubSubCache[type] && (delete this.PubSubCache[type][handler.$uid]);
        }
        for ($type in cache) {
            counter++;
        }
        return !counter && (delete this.PubSubCache[type]);
    }
}


module.exports = {
    formatTime: formatTime,
    request,
    httpBuildQuery,
    httpBuildUrl,
    httpUrlArgs,
    wxPromiseApi,
    wxStorage,
    transformFromWGSToGCJ,
    PubSub
}